﻿using IronPython.Runtime;
using System.Collections;
using System.Linq;
using System.Runtime.InteropServices;

namespace NFox.Pycad.Core.Modules
{

    public static class conv
    {

        public static DispatchWrapper[] ToSafeArray(IEnumerable objs)
        {
            var q =
                from dynamic obj in objs
                select new DispatchWrapper(obj);
            return q.ToArray();
        }

        private static dynamic newvalue(dynamic code, dynamic value = null)
        {
            if (!(code is int))
                code = code.value__;
            return Application.GetValue("acdb.TypedValue")(code, value ?? -1);
        }

        private static List ValueToList(dynamic value)
        {
            List vlst = new List();
            vlst.append(value.TypeCode);
            vlst.append(value.Value);
            return vlst;
        }

        private static dynamic ListToValue(dynamic lst)
        {
            return newvalue(lst[0], lst[1]);
        }

        public static List ToList(IEnumerable rb)
        {
            List lst = new List();
            if (rb != null)
            {
                var q =
                    from dynamic v in rb
                    select ValueToList(v);
                lst.extend(q);
            }
            return lst;
        }

        public static dynamic ToTuple(IEnumerable lst)
        {
            var q = 
                from dynamic v in lst
                select ListToValue(v);
            return new PythonTuple(q);
        }

        public static dynamic ToBuffer(IEnumerable lst)
        {
            return Application.GetValue("acdb.ResultBuffer")(ToTuple(lst));
        }

        public static dynamic ToFilter(IEnumerable lst)
        {
            return Application.GetValue("aced.SelectionFilter")(ToTuple(lst));
        }

        public const string And = "&";
        public const string And2 = "and";
        public const string Or = "|";
        public const string Or2 = "or";
        public const string Not = "~";
        public const string Not2 = "not";
        public const string Xor = "^";
        public const string Xor2 = "xor";

        public static dynamic BuildFilter(params object[] source)
        {
            return 
                Application.GetValue("aced.SelectionFilter")(
                    Filters.OpFilter.Create(source).ToTuple());
        }
        public static dynamic BuildFilter2(params object[] source)
        {
            return Filters.OpFilter.Create(source);
        }


        public static List FromLispData(IEnumerable rb)
        {
            List lst = new List();
            if (rb != null)
                lst.extend(getlist(rb.GetEnumerator()));
            return lst;
        }

        private static IEnumerable getlist(IEnumerator it)
        {
            var lst = new List();
            while(it.MoveNext())
            {
                dynamic v = it.Current;
                var code = (int)v.TypeCode;
                var LispDataType = Application.GetValue("acrx.LispDataType");
                if (code == (int)LispDataType.ListEnd)
                    return lst;
                else if (code == (int)LispDataType.DottedPair)
                    return new PythonTuple(lst);
                else if (code == (int)LispDataType.ListBegin)
                    lst.append(getlist(it));
                else if (code == (int)LispDataType.T_atom)
                    lst.append(true);
                else if (code == (int)LispDataType.Nil)
                    lst.append(false);
                else
                    lst.append(v.Value);
            }
            return lst;
        }

        public static dynamic ToLispData(dynamic obj)
        {
            List lst = new List();
            getbuffer(obj, lst);
            var n = lst.__len__();
            if (n == 0)
                return newvalue(Application.GetValue("acrx.LispDataType").Nil);
            else if (n == 1)
                return lst.ElementAt(0);
            return Application.GetValue("acdb.ResultBuffer")(new PythonTuple(lst));
        }

        public static void getbuffer(dynamic obj, List lst)
        {
            var isinstance = Application.GetValue("isinstance");
            var LispDataType = Application.GetValue("acrx.LispDataType");
            if (obj == null)
                lst.append(newvalue(LispDataType.Nil));
            else if (isinstance(obj, Application.GetValue("acdb.TypedValue")))
                lst.append(obj);
            else if (obj is bool)
            {
                if (obj)
                    lst.append(newvalue(LispDataType.T_atom));
                else
                    lst.append(newvalue(LispDataType.Nil));
            }
            else if (obj is short)
                lst.append(newvalue(LispDataType.Int16, obj));
            else if (obj is int)
                lst.append(newvalue(LispDataType.Int32, obj));
            else if (isinstance(obj, Application.GetValue("int")))
                lst.append(newvalue(LispDataType.Int32, obj));
            else if (isinstance(obj, Application.GetValue("float")))
                lst.append(newvalue(LispDataType.Double, obj));
            else if (isinstance(obj, Application.GetValue("str")))
                lst.append(newvalue(LispDataType.Text, obj));
            else if (isinstance(obj, Application.GetValue("acge.Point2d")))
                lst.append(newvalue(LispDataType.Point2d, obj));
            else if (isinstance(obj, Application.GetValue("acge.Point3d")))
                lst.append(newvalue(LispDataType.Point3d, obj));
            else if (isinstance(obj, Application.GetValue("acdb.ObjectId")))
                lst.append(newvalue(LispDataType.ObjectId, obj));
            else if (isinstance(obj, Application.GetValue("aced.SelectionSet")))
                lst.append(newvalue(LispDataType.SelectionSet, obj));
            else if (obj is IEnumerable)
            {
                lst.append(newvalue(LispDataType.ListBegin));
                foreach (dynamic o in (IEnumerable)obj)
                    getbuffer(o, lst);
                if (obj is PythonTuple)
                    lst.append(newvalue(LispDataType.DottedPair));
                else
                    lst.append(newvalue(LispDataType.ListEnd));
            }

        }


    }

}
